<?php
namespace bee;
define("DB_DONT_FETCH", 0);
define("DB_FETCH_FIRST_ROW", 1);
define("DB_FETCH_FIRST_VALUE", 2);
define("DB_FETCH_ALL", 3);

class connParams
{ public $NAME_OPEN;
  public $NAME_CLOSE;
  public $CONN_STRING;
  public $DB_ENGINE;
  public $username;
  public $password;
}

/**
 *
 * @author dzelenika
 * @todo riješiti konstantom karakterističnosti pojedinih baza (allmost done)
 * @todo multiple database connection handling
 */
class db extends singleton
{
  protected $__class;  // do not delete,  see singleton lin 27
  static protected $__instance;

  protected $__secConnections = array();
  protected $__secConnParams = array();
  protected $__connName;
  public $__NAME_OPEN;
  public $__NAME_CLOSE;
  protected function __construct($name = NULL)
  { try
    { if($name)
      { $db = db::getInstance();
//        print_r($db->__secConnParams);
        $this->__class = new \PDO(
                  $db->__secConnParams[$name]->CONN_STRING,
                  $db->__secConnParams[$name]->username,
                  $db->__secConnParams[$name]->password,
                  array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION));

        $this->__class->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
        $this->__connName = $name;

      } else
      { $cfg = config::getInstance();
        $this->__class = new \PDO(      $cfg->sql__SERVER,
                                        $cfg->sql__USERNAME,
                                        $cfg->sql__PASSWORD,
                          array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION));
                          //, array("Database" => $cfg->sql__DB_NAME) );
                          //echo $cfg->sql__DB_NAME;
//        $this->__class->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
//die(print_r($this->__class));
        if(($cfg->sql__DATABASE_TYPE & DB_ENGINE_MYSQL) == DB_ENGINE_MYSQL)
        { $this->__class->exec("SET NAMES 'UTF8'");
          $this->__NAME_OPEN    = "`";
          $this->__NAME_CLOSE   = "`";
        }
        if(($cfg->sql__DATABASE_TYPE & DB_ENGINE_MSSQL) == DB_ENGINE_MSSQL)
        { $this->__class->exec("SET NOCOUNT ON");//??????
          $this->__NAME_OPEN    = "[";
          $this->__NAME_CLOSE   = "]";
        }
        if(($cfg->sql__DATABASE_TYPE & DB_ENGINE_ORACLE) == DB_ENGINE_ORACLE)
        { $this->__NAME_OPEN    = '"';
          $this->__NAME_CLOSE   = '"';
        }
        foreach ($this->__secConnParams as $key => $param)
        { if(!isset($this->__secConnections[$key]))
          {
          //$this->setSecConnection($key);
          }
        }
      }
    } catch (\PDOException $ex)
    {

      echo ":: ::" . nl2br(print_r($ex, true)) . ":: ::<br />";
    }
  }
/**
 *
 * @param string $name
 * @param string $connString
 * @param string $dbUsername
 * @param string $dbPassword
 * @param int $dbEngine
 */
  public function addSecConnection($name, $connString, $dbUsername, $dbPassword, $dbEngine)
  { $this->__secConnParams[$name] = new connParams();
    $this->__secConnParams[$name]->CONN_STRING    = $connString;
    $this->__secConnParams[$name]->username       = $dbUsername;
    $this->__secConnParams[$name]->password       = $dbPassword;
    $this->__secConnParams[$name]->DB_ENGINE      = $dbEngine;

    if(($dbEngine & DB_ENGINE_MYSQL) == DB_ENGINE_MYSQL)
    { $this->__secConnParams[$name]->NAME_OPEN    = "`";
      $this->__secConnParams[$name]->NAME_CLOSE   = "`";
    }

    if(($dbEngine & DB_ENGINE_MSSQL) == DB_ENGINE_MSSQL)
    { $this->__secConnParams[$name]->NAME_OPEN    = "[";
      $this->__secConnParams[$name]->NAME_CLOSE   = "]";
    }

    if(($dbEngine & DB_ENGINE_ORACLE) == DB_ENGINE_ORACLE)
    { $this->__secConnParams[$name]->NAME_OPEN    = '"';
      $this->__secConnParams[$name]->NAME_CLOSE   = '"';
    }
  }
/**
 *
 * @param string $name
 * @return db
 */
  public function getSecConnection($name)
  { if(isset($this->__secConnections[$name]))
    { return $this->__secConnections[$name];
    }

    if(isset($this->__secConnParams[$name]))
    { $this->__secConnections[$name] = new db($name);
    //die(print_r($this->__secConnections[$name], true) . " //// " . print_r(db::getInstance(), true));
      if(($this->__secConnParams[$name]->DB_ENGINE & DB_ENGINE_MYSQL) == DB_ENGINE_MYSQL)
      { $this->__secConnections[$name]->exec("SET NAMES 'UTF8'");
        $this->__secConnections[$name]->__NAME_OPEN    = "`";
        $this->__secConnections[$name]->__NAME_CLOSE   = "`";
      }

      if(($this->__secConnParams[$name]->DB_ENGINE & DB_ENGINE_MSSQL) == DB_ENGINE_MSSQL)
      { $this->__secConnections[$name]->exec("SET NOCOUNT ON");//??????
        $this->__secConnections[$name]->__NAME_OPEN    = "[";
        $this->__secConnections[$name]->__NAME_CLOSE   = "]";
      }

      if(($this->__secConnParams[$name]->DB_ENGINE & DB_ENGINE_ORACLE) == DB_ENGINE_ORACLE)
      { $this->__secConnections[$name]->__NAME_OPEN    = '"';
        $this->__secConnections[$name]->__NAME_CLOSE   = '"';
      }

      return  $this->__secConnections[$name];
    }

    return false;
  }

  /** dy vratio 2014-11-24
   * @return bee\db
  */
  /*
  public static function getInstance()
  {
    parent::getInstance();
  }
*/

  public function getConnName()
  {
    return $this->__connName;
  }

/*

    public function addConnection($name, $connString, $dbUsername, $dbPassword, $dbEngine)
  { try
    { $this->__secConnParams[$name]                 = new connParams();
      $this->__secConnParams[$name]->CONN_STRING    = $connString;
      $this->__secConnParams[$name]->username       = $dbUsername;
      $this->__secConnParams[$name]->password       = $dbPassword;
      $this->__secConnParams[$name]->DB_ENGINE      = $dbEngine;

      if(($dbEngine & DB_ENGINE_MYSQL) == DB_ENGINE_MYSQL)
      { $this->__secConnParams[$name]->NAME_OPEN    = "`";
        $this->__secConnParams[$name]->NAME_CLOSE   = "`";
      }
      if(($dbEngine & DB_ENGINE_MSSQL) == DB_ENGINE_MSSQL)
      { $this->__secConnParams[$name]->NAME_OPEN    = "[";
        $this->__secConnParams[$name]->NAME_CLOSE   = "]";
      }
      if(($dbEngine & DB_ENGINE_ORACLE) == DB_ENGINE_ORACLE)
      { $this->__secConnParams[$name]->NAME_OPEN    = '"';
        $this->__secConnParams[$name]->NAME_CLOSE   = '"';
      }

      $this->setSecConnection($name);

    } catch (\PDOException $ex)
    {  echo ":: ::" . nl2br(print_r($ex, true)) . ":: ::<br />";
    }
  }



  public function setSecConnection($name)
  { try
    { $cp = $this->__secConnParams[$name];
      $this->__secConnections[$name] = new db("name");
      $this->__secConnections[$name]->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
      if(($cp->DB_ENGINE & DB_ENGINE_MYSQL) == DB_ENGINE_MYSQL)
      {
        $this->__secConnections[$name]->exec("SET NAMES 'UTF8'");
      }
      if(($cp->DB_ENGINE & DB_ENGINE_MSSQL) == DB_ENGINE_MSSQL)
      {
        $this->__secConnections[$name]->exec("SET NOCOUNT ON");//??????
      }
      if(($cp->DB_ENGINE & DB_ENGINE_ORACLE) == DB_ENGINE_ORACLE)
      {
      }
      return $this->__secConnections;
      //print_r(static::$_class );
    } catch (\PDOException $ex)
    {
      echo ":: ::" . nl2br(print_r($ex, true)) . ":: ::<br />";
    }

  }
*/


  /**
   *
   * @param $sql
   * @param $fetch_mode
   * @param $pdo_fetch_style
   * @return unknown_type
   */
  public function execSQL(afterWhere $sql, $fetch_mode = DB_FETCH_FIRST_VALUE, $pdo_fetch_style = \PDO::FETCH_BOTH)
  { //echo $sql->text;
    //print_r($sql->getParams());
    $return='';
    $stmt = $this->getInstance()->prepare($sql->text);
    if($stmt->execute($sql->getParams()))
    { if($fetch_mode          == DB_DONT_FETCH)
      { return true;
      } else if($fetch_mode   == DB_FETCH_FIRST_ROW)
      { $return = $stmt->fetch($pdo_fetch_style);
      } else if($fetch_mode   == DB_FETCH_FIRST_VALUE)
      { $row = $stmt->fetch(\PDO::FETCH_NUM);
        return $row[0];
      } else if($fetch_mode   == DB_FETCH_ALL)
      { $return = $stmt->fetchAll($pdo_fetch_style );
      }
    } else
    { return false;
    }
    foreach ($return as &$v)
    { if(is_array($v))
      { foreach ($v as &$av)
        { //$av = iconv("Windows-1250", "UTF-8", $av);
        	//$av = iconv("UTF-16", "UTF-8", $av);
        }
      } else
      { //$v = iconv("Windows-1250", "UTF-8", $v);
      	//$v = iconv("UTF-16", "UTF-8", $v);
      }
    }
    return $return;
  }
  /**
   *
   * @param $DAORow
   * @param $sql
   * @param $fetch_mode
   * @param $pdo_fetch_style
   * @return unknown_type
   */
  public function execSQLByDAORow(DAO $DAORow, afterWhere $sql = NULL, $fetch_mode = DB_FETCH_FIRST_VALUE, $pdo_fetch_style = \PDO::FETCH_BOTH)
  { $where_refl = new \ReflectionClass(get_class($DAORow));
    $cls_props = $where_refl->getProperties(\ReflectionProperty::IS_PUBLIC);
    $query_arr = array();
    $param_array = array();

    foreach($cls_props as $prop)
    { if(!empty($DAORow->{$prop->name}))
      { $query_arr[$prop->name] = $this->__NAME_OPEN . $prop->name . $this->__NAME_CLOSE . " = :" . $prop->name ;// . $daoRow->prepareSQL($daoRow->{$prop->name}, true);
        $param_array[":" .$prop->name] = $DAORow->{$prop->name};
      }
    }

    $sqt = $sql->text . (  $query_arr ? (" AND " . implode(" AND ", $query_arr)) : " ");
    $stmt = $this->getInstance()->prepare($sqt);
    //echo $sqt;
    if($stmt->execute(array_merge($sql->getParams(), $param_array)))
    { if($fetch_mode          == DB_DONT_FETCH)
      { return true;
      } else if($fetch_mode   == DB_FETCH_FIRST_ROW)
      { $return = $stmt->fetch($pdo_fetch_style);
      } else if($fetch_mode   == DB_FETCH_FIRST_VALUE)
      { $row = $stmt->fetch(\PDO::FETCH_NUM);
        return $row[0];
      } else if($fetch_mode   == DB_FETCH_ALL)
      { $return = $stmt->fetchAll($pdo_fetch_style);
      }
    } else
    { return false;
    }
    foreach ($return as &$v)
    { if(is_array($v))
      { foreach ($v as &$av)
        { // //$av = iconv("Windows-1250", "UTF-8", $av);
        }
      } else
      { // //$v = iconv("Windows-1250", "UTF-8", $v);
      }
    }
    return $return;
  }
  public function cleanUp()
  { //echo(print_r($this, true));
    $this->__secConnections = array();
    $this->__class = NULL;
    //die(print_r($this, true));
  }
}

